package com.song.gencode.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.song.gencode.dao.GencodeMapper;
import com.song.gencode.entity.FieldInfo;
import com.song.gencode.entity.Gencode;

import basic.commons.util.StringUtil;
import basic.commons.util.ZipUtil;

/**
 * Created by keyuwang on 2016/11/29.
 */
@Service
@Transactional
public class GencodeService {
	
	@Autowired
    private GencodeMapper mapper;

    public String gencode(String tableName,String packageName) throws IOException {

        if (StringUtil.isNotEmpty(tableName)) {
            if(StringUtil.isEmpty(packageName)){
                packageName=getClassname(tableName).toLowerCase();
            }
            List<Gencode> list = getAllColumns(tableName);
            //生成目标目录
            String genPath ="D:/gencode/";// ConfigUtil.get(ConfigUtil.PathGencode);
            String classname = this.getClassname(tableName);
            String filePath = genPath + classname;
            File file = new File(filePath);
            if (file.exists()) {
                deleteDirectory(filePath);
            }
            file.mkdirs();
            // 1、生成entity
            genEntity(filePath, tableName, list);
            // 2、生成auto dao
            genAutoMapper(filePath, tableName, list,packageName);
            // 3、生成manual dao
            // 4、生成service
            genService(filePath,tableName, list);
            // 5、生成provider
            genProvider(filePath,tableName, list,packageName);
            // 6、生成controller
            genController(filePath, tableName, list,packageName);
            
            String targetPath = genPath+"/" + System.currentTimeMillis()+ ".zip";
            ZipUtil.compress(targetPath, filePath);
            return targetPath;
        }
        return "";
    }

    private List<Gencode> getAllColumns(String tableName) {
        List<Gencode> columns = this.mapper.showFullColumns(tableName);
        return columns;
    }



    /**
     * generate entity
     *
     * @param tableName
     * @param list
     * @throws IOException
     */
    private void genEntity(String targetPath ,String tableName, List<Gencode> list) throws IOException {
        Template template = getTemplateByName("entity.vm");
        VelocityContext ctx = new VelocityContext();
        String className = getClassname(tableName);
        ctx.put("className", className);
        Map<String, Object> resultMap = getFields(list);
        ctx.put("packageList", resultMap.get("packageList"));
        ctx.put("fieldList", resultMap.get("fieldList"));
        StringWriter writer = getWriter(template, ctx);
        targetPath = targetPath + "/entity";
        File file = new File(targetPath);
        if (file.exists()) {
           deleteDirectory(targetPath);
        }
        file.mkdir();
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(targetPath + "/" + className + ".java", true), "UTF-8");
        osw.write(writer.toString());
        osw.flush();
        osw.close();
    }


    /**
     * 生成自动封装的Mapper.xml
     * @param tableName
     * @param list
     * @throws IOException
     */
    private void genAutoMapper(String targetPath, String tableName, List<Gencode> list,String packageName) throws IOException{
        Template template = getTemplateByName("automapper.vm");
        VelocityContext ctx = new VelocityContext();
        ctx.put("namespace", "com.qingke.pemapp.dao."+getClassname(tableName)+"Mapper");// 设置路径
        String className = getClassname(tableName);
        ctx.put("resultClass", "com.qingke.pemapp.dao."+className);
        ctx.put("tableName", tableName);
        ctx.put("path","com.qingke.pemapp.dao");// 设置路径
        ctx.put("className", className);// 类名称
        Map<String, Object> resultMap = getFields(list);
        ctx.put("packageList", resultMap.get("packageList"));
        ctx.put("fieldList", resultMap.get("fieldList"));
        StringWriter writer = getWriter(template, ctx);
        targetPath=targetPath+"/"+"com.qingke.pemapp.dao";
        File file=new File(targetPath);
        if(file.exists()){
            deleteDirectory(targetPath);
        }
        file.mkdir();
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( targetPath+"/"+className+"Mapper.xml", true),"UTF-8");
        osw.write(writer.toString());
        osw.flush();
        osw.close();
        template = getTemplateByName("autojava.vm");
        writer = getWriter(template, ctx);
        osw = new OutputStreamWriter(new FileOutputStream( targetPath+"/"+className+"Mapper.java", true),"UTF-8");
        osw.write(writer.toString());
        osw.flush();
        osw.close();
    }


    private void genService(String targetPath,String tableName, List<Gencode> list) throws IOException{
        Template template = getTemplateByName("service.vm");
        VelocityContext ctx = new VelocityContext();
        String className = getClassname(tableName);
        ctx.put("className", className);// 类名称
        StringWriter writer = getWriter(template, ctx);
        targetPath=targetPath+"/service";
        File file=new File(targetPath);
        if(file.exists()){
            deleteDirectory(targetPath);
        }
        file.mkdir();
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( targetPath+"/"+className+"Service.java", true),"UTF-8");
        osw.write(writer.toString());
        osw.flush();
        osw.close();
    }

    private void genProvider(String targetPath, String tableName, List<Gencode> list,String packageName) throws IOException{
        Template template = getTemplateByName("provider.vm");
        VelocityContext ctx = new VelocityContext();
        ctx.put("path",  packageName);// 设置路径
        String className = getClassname(tableName);
        ctx.put("className", className);// 类名称
        StringWriter writer = getWriter(template, ctx);
        targetPath=targetPath+"/provider";
        File file=new File(targetPath);
        if(file.exists()){
            deleteDirectory(targetPath);
        }
        file.mkdir();
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( targetPath+"/"+className+"Provider.java", true),"UTF-8");
        osw.write(writer.toString());
        osw.flush();
        osw.close();
    }


    private void genController(String targetPath, String tableName, List<Gencode> list,String packageName) throws IOException{
        Template template = getTemplateByName("controller.vm");
        VelocityContext ctx = new VelocityContext();
        ctx.put("path", packageName);// 设置路径
        String className = getClassname(tableName);
        ctx.put("className", className);// 类名称
        StringBuilder sb = new StringBuilder(className);
        sb.setCharAt(0, Character.toLowerCase(className.charAt(0)));
        ctx.put("classNameLowerCase", sb.toString());// 类名称
        StringWriter writer = getWriter(template, ctx);
        targetPath=targetPath+"/web";
        File file=new File(targetPath);
        if(file.exists()){
            deleteDirectory(targetPath);
        }
        file.mkdir();

        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( targetPath+"/"+className+"Controller.java", true),"UTF-8");
        osw.write(writer.toString());
        osw.flush();
        osw.close();
    }

    /**
     * 根据表名称，显示表中所有字段信息
     *
     * @param tableName
     * @return
     */
    public List<Gencode> showFullColumns(String tableName) {
        List<Gencode> list = this.mapper.showFullColumns(tableName);
        return list;
    }

    /**
     * 根据模板名称，获取模板
     *
     * @param templateName
     * @return
     * @throws IOException
     */
    private Template getTemplateByName(String templateName) throws IOException {
        VelocityEngine ve = new VelocityEngine();
        Properties p = new Properties();
        p.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
        p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
        p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
        p.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, "D:/velocity/");
        p.put("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
        Template t=null;
        try {
			ve.init(p);
//			t = ve.getTemplate("/velocity/" + templateName);
			t = ve.getTemplate(templateName);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return t;
    }

    /**
     * 根据模板生成流文件
     *
     * @param template
     * @param ctx
     * @return
     * @throws IOException 
     * @throws MethodInvocationException 
     * @throws ParseErrorException 
     * @throws ResourceNotFoundException 
     */
    private StringWriter getWriter(Template template, VelocityContext ctx) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, IOException {
        StringWriter sw = new StringWriter();
        template.merge(ctx, sw);
        return sw;
    }

    /**
     * 获取类名称
     *
     * @param tableName
     * @return
     */
    private String getClassname(String tableName) {
        String[] names = tableName.split("_");
        if(names.length==1){
            StringBuilder subword = new StringBuilder(names[0]);
            subword.setCharAt(0, Character.toUpperCase(names[0].charAt(0)));
            return subword.toString();
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i < names.length; i++) {
            StringBuilder subword = new StringBuilder(names[i]);
            subword.setCharAt(0, Character.toUpperCase(names[i].charAt(0)));
            sb.append(subword);
        }
        return sb.toString();
    }

    public Map<String, Object> getFields(List<Gencode> list) {
        Map<String, String> packageMap = new HashMap<String, String>();
        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
        for (Gencode gencode : list) {
            FieldInfo fieldInfo = getFieldInfo(gencode);
            fieldList.add(fieldInfo);
            if (fieldInfo.getDatatype().equals("Date")) {
                packageMap.put("java.util.Date", "1");
            }
        }

        List<String> packageList = new ArrayList<String>();
        Set<String> keySet = packageMap.keySet();
        for (String pk : keySet) {
            packageList.add(pk);
        }

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("packageList", packageList);
        resultMap.put("fieldList", fieldList);
        return resultMap;
    }

    private FieldInfo getFieldInfo(Gencode gencode) {
        FieldInfo fieldInfo = new FieldInfo();
        String fieldName = gencode.getField().toLowerCase();
        String[] names = fieldName.split("_");
        StringBuilder sb = null;
        String fieldname;
        String getName;
        String setName;
        if (names.length > 1) {
            fieldname = names[0];
            for (int i = 1; i < names.length; i++) {
                sb = new StringBuilder(names[i]);
                sb.setCharAt(0, Character.toUpperCase(names[i].charAt(0)));
                fieldname = fieldname + sb;
            }
        } else {
            fieldname = names[0];
        }
        sb = new StringBuilder(fieldname);
        sb.setCharAt(0, Character.toUpperCase(fieldname.charAt(0)));
        getName = "get" + sb.toString();
        setName = "set" + sb.toString();
        fieldInfo.setFieldname(fieldname);
        fieldInfo.setGetName(getName);
        fieldInfo.setSetName(setName);
        fieldInfo.setDatatype(getDatetype(gencode.getType()));
        fieldInfo.setComment(gencode.getComment());
        return fieldInfo;
    }

    /**
     * 获取数据类型
     *
     * @param type
     * @return
     */
    private String getDatetype(String type) {
        if (type.startsWith("int")) {
            return "Integer";
        } else if (type.startsWith("varchar")) {
            return "String";
        } else if (type.startsWith("datetime")) {
            return "Date";
        } else if (type.startsWith("double")) {
            return "Double";
        } else if (type.startsWith("float")) {
            return "Float";
        } else {
            return "String";
        }
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     *
     * @param sPath 被删除目录的文件路径
     * @return 目录删除成功返回true，否则返回false
     */
    public void deleteDirectory(String sPath) {
        //如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (dirFile.exists() && dirFile.isDirectory()) {
            //删除文件夹下的所有文件(包括子目录)
            File[] files = dirFile.listFiles();
            for (int i = 0; i < files.length; i++) {
                //删除子文件
                if (files[i].isFile()) {
                    deleteFile(files[i].getAbsolutePath());

                } //删除子目录
                else {
                    deleteDirectory(files[i].getAbsolutePath());
                }
            }
            //删除当前目录
            dirFile.delete();

        }

    }


    /**
     * 删除单个文件
     *
     * @param sPath 被删除文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */

    public void deleteFile(String sPath) {

        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
        }
    }
}
